/* passwd - change a passwd		Author: Adri Koppes */

#include "signal.h"
#include "pwd.h"

char    pwd_file[] = "/etc/passwd";
char    pw_tmp[] = "/etc/pwtemp";
char    bad[] = "Permission denied\n";
char buf[512];

main (argc, argv)
int   argc;
char *argv[];
{
	int     uid, cn, n;
	int     fpin, fpout;
	long    salt;
	struct  passwd  *pwd, *getpwnam (), *getpwuid (), *getpwent ();
	char    name[9], password[14], sl[2];
	char   *getpass (), *crypt ();

	uid = getuid ();

	if (!access (pw_tmp, 0)) {
		std_err("Temporary file in use.\nTry again later\n");
		exit (1);
	}

	if (argc < 2) {
		pwd = getpwuid (uid);
		strcpy (name, pwd->pw_name);
	} else {
		strcpy (name, argv[1]);
		pwd = getpwnam (name);
	}
	if (!pwd || ((uid != pwd->pw_uid) && uid)) {
		std_err(bad);
		exit (1);
	}
	signal (SIGHUP, SIG_IGN);
	signal (SIGINT, SIG_IGN);
	signal (SIGQUIT, SIG_IGN);
	signal (SIGTERM, SIG_IGN);
	prints("Changing password for %s\n",name);
	if (pwd->pw_passwd[0] && uid)
		if (strcmp (pwd->pw_passwd, crypt (getpass ("Old password: "), pwd->pw_passwd))) {
			std_err(bad);
			exit (1);
		}
	strcpy (password, getpass ("New password: "));
	if (strcmp (password, getpass ("Retype password: "))) {
		std_err("Passwords don't match\n");
		exit (1);
	}
	time (&salt);
	sl[0] = (salt & 077) + '.';
	sl[1] = ((salt >> 6) & 077) + '.';
	for (cn = 0; cn < 2; cn++) {
		if (sl[cn] > '9')
			sl[cn] += 7;
		if (sl[cn] > 'Z')
			sl[cn] += 6;
	}
	if (password[0])
		strcpy (password, crypt (password, sl));
	umask (0);
	close(1);
	fpout = creat(pw_tmp,0600);
	if (fpout != 1) {
		std_err("Can't create temporary file\n");
		exit (1);
	}
	setpwent ();
	while ((pwd = getpwent ()) != 0) {
		if (!strcmp (name, pwd->pw_name)) pwd->pw_passwd = password;
		prints("%s:%s:%s:",pwd->pw_name,pwd->pw_passwd,itoa(pwd->pw_uid));
		prints("%s:%s:%s:%s\n", itoa(pwd->pw_gid),pwd->pw_gecos, pwd->pw_dir,
				pwd->pw_shell );
	}
	endpwent ();
	close(0);
	if ((fpin = open (pw_tmp, 0)) != 0) {
		std_err("Can't reopen temporary file\n");
		exit (1);
	}
	close (fpout);
	if ((fpout = open(pwd_file, 2)) < 0) {
		std_err("Can't recreate password file\n");
		unlink (pw_tmp);
		exit (1);
	}
	while (1) {
		n = read(fpin, buf, 512);
		if (n <= 0) break;
		write(1, buf, n);
	}

	fclose (fpin);
	fclose (fpout);
	unlink (pw_tmp);
}
